Skip to content

feat: white-label branding support#18

Open
pthmas wants to merge 6 commits intomainfrom
pierrick/white-labeling
Open

feat: white-label branding support#18
pthmas wants to merge 6 commits intomainfrom
pierrick/white-labeling

Conversation

@pthmas
Copy link
Collaborator

@pthmas pthmas commented Feb 25, 2026

Summary

  • Add runtime-configurable branding via 7 optional env vars (CHAIN_NAME, CHAIN_LOGO_URL, ACCENT_COLOR, BACKGROUND_COLOR_DARK, BACKGROUND_COLOR_LIGHT, SUCCESS_COLOR, ERROR_COLOR)
  • New backend GET /api/config endpoint serves branding config from environment variables
  • Frontend BrandingContext fetches config once on load, applies CSS custom properties for accent colors and derives surface palettes from background colors
  • Logo, chain name, favicon, and page title update dynamically
  • All values optional — defaults match current Atlas branding when unset

Test plan

  • Set custom CHAIN_NAME and ACCENT_COLOR in .env, verify title/links/buttons change
  • Set BACKGROUND_COLOR_DARK / BACKGROUND_COLOR_LIGHT, verify surface colors adapt in both themes
  • Set CHAIN_LOGO_URL pointing to mounted branding asset, verify logo in navbar and welcome page
  • Verify with no branding env vars set, UI looks identical to current Atlas
  • Test dark/light theme toggle with custom backgrounds
  • Verify bunx vite build succeeds
  • Verify docker compose build && docker compose up -d works end-to-end

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • White-label branding support: customize chain name, logo, and accent colors via environment variables
    • New branding API endpoint dynamically serves configuration to the frontend
    • Color theming system automatically derives complete palette from a single base color
  • Documentation

    • Added white-labeling configuration and setup guide

Add runtime-configurable branding via environment variables so each
chain deployment can customize name, logo, colors without rebuilding.

Backend: new /api/config endpoint serving branding config from env vars
(CHAIN_NAME, CHAIN_LOGO_URL, ACCENT_COLOR, BACKGROUND_COLOR_DARK,
BACKGROUND_COLOR_LIGHT, SUCCESS_COLOR, ERROR_COLOR).

Frontend: BrandingContext fetches config once on load and applies CSS
custom properties for accent, success/error, and derived surface
palettes. Logo, chain name, favicon, and page title update dynamically.
All values are optional with sensible defaults matching current Atlas
branding.
@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Warning

Rate limit exceeded

@pthmas has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 53 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between bc045f9 and 318f121.

📒 Files selected for processing (3)
  • backend/crates/atlas-api/src/main.rs
  • docs/WHITE_LABELING.md
  • frontend/src/utils/color.ts
📝 Walkthrough

Walkthrough

This PR introduces white-label branding customization across the application stack. It adds environment variables for configurable branding (chain name, logo URL, accent and background colors), exposes a new /api/config backend endpoint to serve this configuration, and implements frontend context, hooks, and API layer to consume and apply dynamic branding. A color utility module derives full palettes from base colors, which are applied as CSS variables for dynamic theming without frontend rebuild.

Changes

Cohort / File(s) Summary
Configuration
.env.example, docker-compose.yml
Add branding environment variables (CHAIN_NAME, CHAIN_LOGO_URL, ACCENT_COLOR, BACKGROUND_COLOR_DARK/LIGHT, SUCCESS_COLOR, ERROR_COLOR) with defaults; mount branding directory to frontend container.
Backend API
backend/crates/atlas-api/src/handlers/config.rs, backend/crates/atlas-api/src/handlers/mod.rs, backend/crates/atlas-api/src/main.rs
Introduce BrandingConfig struct with serializable branding fields; add GET /api/config handler; extend AppState with branding fields initialized from environment variables.
Frontend API & Context
frontend/src/api/config.ts, frontend/src/context/branding-context.ts, frontend/src/context/BrandingContext.tsx, frontend/src/hooks/useBranding.ts
Add BrandingConfig interface and getConfig() fetch function; create BrandingContext and BrandingProvider with config fetching, color derivation, and CSS variable application; introduce useBranding hook for context consumption.
Frontend UI Integration
frontend/src/App.tsx, frontend/src/components/Layout.tsx, frontend/src/pages/WelcomePage.tsx
Wrap app with BrandingProvider; update Layout and WelcomePage to use dynamic branding (chainName, logoUrl) for logo rendering and accessibility attributes.
Frontend Styling
frontend/src/index.css, frontend/src/utils/color.ts, frontend/tailwind.config.js
Introduce color.ts utility module with deriveSurfaceShades() and applyPalette() to generate full color palettes from base colors; update CSS to use dynamic color variables; replace hardcoded colors in Tailwind config with CSS variable lookups.
Infrastructure
frontend/nginx.conf
Add Nginx location block to serve branding assets at /branding/ with 1-hour cache expiry.
Documentation
docs/WHITE_LABELING.md, README.md
Add comprehensive white-labeling documentation covering environment variables, Docker integration, color system, API usage, and examples; cross-reference white-labeling in README Configuration section.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client (Browser)
    participant App as Frontend App
    participant API as Backend /api/config
    participant AppState as AppState (Config)
    
    Client->>App: Load Application
    App->>App: Mount BrandingProvider
    activate App
    App->>API: GET /api/config
    activate API
    API->>AppState: Read branding fields
    AppState-->>API: Return branding config
    API-->>App: JSON BrandingConfig
    deactivate API
    App->>App: deriveSurfaceShades(baseColor)
    App->>App: applyPalette(derivedColors)
    App->>App: Set CSS custom properties
    deactivate App
    App-->>Client: Render with custom branding
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

  • feat: light mode #12 — Modifies theming stack provider wrapping (App.tsx), CSS variables, and color tokens in shared theming/branding code paths.

Suggested reviewers

  • tac0turtle

Poem

🐰 Hop into custom branding, dear explorer,
Colors dance from config, not code—much bolder!
Chain names and logos bloom from env's store,
CSS speaks with variables evermore!
One base hue begets a palette so grand,
White-label magic across the land! 🎨✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: white-label branding support' clearly and concisely summarizes the main change: adding runtime-configurable white-label branding to the application.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pierrick/white-labeling

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

pthmas and others added 3 commits February 25, 2026 21:54
- Run cargo fmt to wrap long env var lines in main.rs
- Remove unused rgbToHex function and mode parameter in color.ts
- Fix react-refresh/only-export-components by separating BrandingContext
  definition into branding-context.ts and useBranding hook into its own file

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Explain how to customize chain name, logo, and color scheme via
environment variables. Includes examples for blue, green, and
minimal configurations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The default branding comes from ev-node, not Atlas.
@pthmas pthmas marked this pull request as ready for review February 27, 2026 13:41
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
.env.example (1)

23-27: Consider quoting hex color values for parser compatibility.

Some .env parsers may interpret # as the start of a comment, even without a preceding space. Quoting ensures the full hex value is captured.

🔧 Suggested fix
-ACCENT_COLOR=#dc2626                  # Primary accent color (links, buttons, active states)
-BACKGROUND_COLOR_DARK=#050505         # Dark mode base background
-BACKGROUND_COLOR_LIGHT=#f4ede6        # Light mode base background
-SUCCESS_COLOR=#22c55e                 # Success indicator color
-ERROR_COLOR=#dc2626                   # Error indicator color
+ACCENT_COLOR="#dc2626"                # Primary accent color (links, buttons, active states)
+BACKGROUND_COLOR_DARK="#050505"       # Dark mode base background
+BACKGROUND_COLOR_LIGHT="#f4ede6"      # Light mode base background
+SUCCESS_COLOR="#22c55e"               # Success indicator color
+ERROR_COLOR="#dc2626"                 # Error indicator color
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env.example around lines 23 - 27, The hex color values in the .env example
(ACCENT_COLOR, BACKGROUND_COLOR_DARK, BACKGROUND_COLOR_LIGHT, SUCCESS_COLOR,
ERROR_COLOR) may be parsed incorrectly due to the leading #; update each
variable to wrap the hex value in quotes (e.g., change ACCENT_COLOR=#dc2626 to
ACCENT_COLOR="#dc2626") and apply the same quoting to any other color vars in
the file so parsers don't treat # as a comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/crates/atlas-api/src/main.rs`:
- Line 51: The CHAIN_NAME env handling currently accepts an empty string; change
the retrieval logic for chain_name (the variable initialized where
std::env::var("CHAIN_NAME") is called) to treat empty or whitespace-only values
as unset by checking the env var result and falling back to "Atlas" when the
value is Err or when the Ok string is empty/only whitespace (e.g., trim and test
is_empty), so chain_name uses the default branding unless a non-empty value is
provided.

In `@docs/WHITE_LABELING.md`:
- Around line 5-13: The docs currently conflict on the default branding: the
intro claims the explorer falls back to "ev-node" branding while the CHAIN_NAME
table lists the default as "Atlas"; pick one canonical default and make the text
consistent by updating either the opening paragraph (replace "ev-node" with
"Atlas") or the table default (replace "`Atlas`" with "`ev-node`"), and ensure
the CHAIN_NAME entry and any other references to default branding in
WHITE_LABELING.md use that same value.

In `@frontend/src/context/BrandingContext.tsx`:
- Line 76: The forEach callback currently implicitly returns the result of
root.style.removeProperty(v) (vars.forEach(v => root.style.removeProperty(v));)
which violates the useIterableCallbackReturn rule; change the callback to a
block body so it returns void (e.g., vars.forEach(v => {
root.style.removeProperty(v); });) making sure the callback for vars.forEach
does not return any value.

In `@frontend/src/utils/color.ts`:
- Around line 34-40: Normalize and validate the input inside hexToRgb: trim and
ensure it starts with or without '#', accept 3- or 6-character hex forms (expand
3-char shorthand to 6-char), verify the final cleaned string is exactly 6 hex
digits (0-9a-f/A-F), and if validation fails either throw a clear error or
return a safe default RGB; then parse r/g/b with parseInt on the validated
string to avoid NaN channels. Ensure these checks are implemented in hexToRgb so
downstream CSS variable generation never receives invalid channel values.

---

Nitpick comments:
In @.env.example:
- Around line 23-27: The hex color values in the .env example (ACCENT_COLOR,
BACKGROUND_COLOR_DARK, BACKGROUND_COLOR_LIGHT, SUCCESS_COLOR, ERROR_COLOR) may
be parsed incorrectly due to the leading #; update each variable to wrap the hex
value in quotes (e.g., change ACCENT_COLOR=#dc2626 to ACCENT_COLOR="#dc2626")
and apply the same quoting to any other color vars in the file so parsers don't
treat # as a comment.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a488e55 and bc045f9.

📒 Files selected for processing (18)
  • .env.example
  • README.md
  • backend/crates/atlas-api/src/handlers/config.rs
  • backend/crates/atlas-api/src/handlers/mod.rs
  • backend/crates/atlas-api/src/main.rs
  • docker-compose.yml
  • docs/WHITE_LABELING.md
  • frontend/nginx.conf
  • frontend/src/App.tsx
  • frontend/src/api/config.ts
  • frontend/src/components/Layout.tsx
  • frontend/src/context/BrandingContext.tsx
  • frontend/src/context/branding-context.ts
  • frontend/src/hooks/useBranding.ts
  • frontend/src/index.css
  • frontend/src/pages/WelcomePage.tsx
  • frontend/src/utils/color.ts
  • frontend/tailwind.config.js

- Treat empty/whitespace CHAIN_NAME as unset, falling back to "Atlas"
- Validate hex input in hexToRgb: trim, support 3-char shorthand, reject
  malformed values to avoid NaN CSS variables
Make the table header and intro consistent so operators understand
that "Atlas" is the default ev-node branding, not a separate brand.
@pthmas pthmas requested a review from tac0turtle February 27, 2026 14:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant